package com.xzy.learn.spring.lookup;

import com.xzy.learn.spring.entity.User;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Stream;

/**
 * 依赖查找的安全性
 * <p>
 * Note：推荐使用 ObjectProvider 进行依赖查找
 *
 * @author xzy.xiao
 * @date 2022/6/7  10:46
 */
public class LookupSafetyDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(LookupSafetyDemo.class);
        displayBeanFactoryGetBean(annotationConfigApplicationContext);
        displayObjectFactoryGetObject(annotationConfigApplicationContext);
        displayObjectProviderGetIfAvailable(annotationConfigApplicationContext);
        displayListableBeanFactoryGetBeansOfType(annotationConfigApplicationContext);
        displayObjectProviderStream(annotationConfigApplicationContext);
    }

    /*==================== 单一类型查找 ====================*/

    /**
     * {@link BeanFactory#getBean}（不安全）
     */
    public static void displayBeanFactoryGetBean(BeanFactory beanFactory) {
        User user = printBeanException(() -> beanFactory.getBean(User.class));
        System.out.println(user);
    }

    /**
     * {@link ObjectFactory#getObject()}（不安全）
     */
    public static void displayObjectFactoryGetObject(ApplicationContext applicationContext) {
        ObjectFactory<User> userObjectFactory = applicationContext.getBeanProvider(User.class);
        User user = printBeanException(userObjectFactory::getObject);
        System.out.println(user);
    }

    /**
     * {@link ObjectProvider#getIfAvailable()}（安全）
     */
    public static void displayObjectProviderGetIfAvailable(ApplicationContext applicationContext) {
        ObjectProvider<User> userBeanProvider = applicationContext.getBeanProvider(User.class);
        User user = printBeanException(() -> userBeanProvider.getIfAvailable(User::new));
        System.out.println(user);
    }

    /*==================== 集合类型查找 ====================*/

    /**
     * {@link org.springframework.beans.factory.ListableBeanFactory#getBeansOfType(Class)}（安全）
     */
    public static void displayListableBeanFactoryGetBeansOfType(ListableBeanFactory listableBeanFactory) {
        Map<String, User> userMap = printBeanException(() -> listableBeanFactory.getBeansOfType(User.class));
        System.out.println(userMap);
    }

    /**
     * {@link ObjectProvider#stream()}（安全）
     */
    public static void displayObjectProviderStream(ApplicationContext applicationContext) {
        ObjectProvider<User> userBeanProvider = applicationContext.getBeanProvider(User.class);
        Stream<User> stream = printBeanException(userBeanProvider::stream);
        System.out.println(stream);
    }

    /*==================== SUPPORT ====================*/

    public static <T> T printBeanException(Supplier<T> supplier) {
        try {
            return supplier.get();
        } catch (BeansException e) {
            e.printStackTrace();
        }
        return null;
    }

}
